package com.example.questionsystem.modules.qu.util;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import com.example.questionsystem.core.exception.ServiceException;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

public class QuestionParser {
    // 系统支持的小题题目类型集合（需与整体题型保持一致）
    private static final java.util.Set<String> SUPPORTED_TYPES = new java.util.LinkedHashSet<>(
            java.util.Arrays.asList(
                    "不定项选择题", "判断题", "对错题", "单项选择题", "单选题",
                    "多项选择题", "多选题", "填空题", "计算题", "简答题",
                    "表格题", "综合题", "不定项", "写作题", "作文题"
            )
    );

    // 规范化映射：将同义词映射为系统认可的标准题型名
    private static final java.util.Map<String, String> TYPE_SYNONYMS = new java.util.HashMap<>();
    static {
        TYPE_SYNONYMS.put("单选题", "单项选择题");
        TYPE_SYNONYMS.put("多选题", "多项选择题");
        TYPE_SYNONYMS.put("对错题", "判断题");
        TYPE_SYNONYMS.put("作文题", "写作题");
        TYPE_SYNONYMS.put("不定项选择题", "不定项");
        TYPE_SYNONYMS.put("计算题", "综合题");
        
    }

    // 系统认可的标准题型集合（与 QuestionTypeEnum 保持一致的中文名）
    private static final java.util.Set<String> CANONICAL_TYPES = new java.util.LinkedHashSet<>(
            java.util.Arrays.asList(
                    "判断题", "单项选择题", "多项选择题", "不定项", "填空题",
                    "简答题", "分析题", "写作题", "速录题", "综合题", "表格题"
            )
    );

    // 将输入题型名映射为标准题型名
    private static String normalizeTypeName(String name) {
        if (name == null) return null;
        String mapped = TYPE_SYNONYMS.getOrDefault(name, name);
        return mapped;
    }

    // 小题对象
    public static class SubQuestion {
        private final String type;   // 题型，如：简答题、单项选择题、计算题
        private final String html;   // 小题 HTML 内容

        public SubQuestion(String type, String html) {
            this.type = type;
            this.html = html;
        }

        public String getType() {
            return type;
        }

        public String getHtml() {
            return html;
        }

        @Override
        public String toString() {
            return "SubQuestion{" +
                    "type='" + type + '\'' +
                    ", html='" + html + '\'' +
                    '}';
        }
    }

    // 整体题目对象
    public static class Question {
        private final String stemHtml;             // 题干 HTML
        private final List<SubQuestion> subQuestions; // 小题集合

        public Question(String stemHtml, List<SubQuestion> subQuestions) {
            this.stemHtml = stemHtml;
            this.subQuestions = subQuestions;
        }

        public String getStemHtml() {
            return stemHtml;
        }

        public List<SubQuestion> getSubQuestions() {
            return subQuestions;
        }
    }

    /**
     * 解析题目
     */
    public static Question parseQuestion(String inputFile) throws Exception {
        Document doc = Jsoup.parse(inputFile, StandardCharsets.UTF_8.name());

        boolean inStem = false;
        boolean inSubQ = false;
        boolean foundStemMarker = false;     // 是否出现【题干】
        boolean foundEndMarker = false;      // 是否出现【题目结束】
        String questionIndex = null;         // 题号（如 44），用于错误提示定位
        boolean foundTypeSubMarker = false;  // 是否出现过【题目类型】（小题起始）
        java.util.List<String> parenSubNums = new java.util.ArrayList<>(); // 捕获括号编号（兼容旧逻辑）
        java.util.Set<String> missingTypeSubNums = new java.util.LinkedHashSet<>(); // 记录缺少类型的小题编号（发生在进入小题段之后）
        java.util.Set<String> preStemParenNums = new java.util.LinkedHashSet<>();   // 题干阶段出现的括号编号（不作为错误，除非全题没有任何类型标识）
        boolean subSectionStarted = false;  // 是否已进入小题段（见到过【题目类型】）

        StringBuilder stemBuilder = new StringBuilder();
        List<SubQuestion> subQuestions = new ArrayList<>();
        java.util.List<String> errors = new java.util.ArrayList<>();

        String currentType = null;
        StringBuilder subQBuilder = new StringBuilder();

        for (Element element : doc.body().children()) {
            String html = element.outerHtml();
            String plain = element.text().trim();

            // 题干开始
            if (plain.contains("【题干】")) {
                inStem = true;
                foundStemMarker = true;
                // 提取题号（如："【题干】44．"）
                Matcher m = Pattern.compile("【题干】\\s*([0-9]+)[．\\.,，]").matcher(plain);
                if (m.find()) {
                    questionIndex = m.group(1);
                }
                String cleaned = html.replace("【题干】", "");
                stemBuilder.append(cleaned);
                continue;
            }

            // 题目结束
            if (plain.contains("【题目结束】")) {
                foundEndMarker = true;
                if (inSubQ && currentType != null) {
                    subQuestions.add(new SubQuestion(currentType, subQBuilder.toString()));
                }
                break;
            }

            // 小题开始（带类型）
            if (plain.matches(".*【.*题】.*")) {
                if (inSubQ && currentType != null) {
                    subQuestions.add(new SubQuestion(currentType, subQBuilder.toString()));
                    subQBuilder.setLength(0);
                }
                inStem = false;
                inSubQ = true;
                foundTypeSubMarker = true;
                subSectionStarted = true;

                // 校验并解析小题类型 + 序号：格式需为 【题目类型】（数字） 或 【题目类型】(数字)
                String typeName = null;
                String subNum = null;
                Matcher sm = Pattern.compile(".*【([\\u4e00-\\u9fa5]+题)】[（(]\\s*(\\d+)\\s*[)）].*").matcher(plain);
                if (sm.find()) {
                    typeName = sm.group(1);
                    subNum = sm.group(2);
                } else {
                    // 兼容检测：如果是【题目类型】数字. 的形式，明确提示需要括号
                    Matcher am = Pattern.compile(".*【([\\u4e00-\\u9fa5]+题)】\\s*(\\d+)[．\\.,，].*").matcher(plain);
                    if (am.find()) {
                        typeName = am.group(1);
                        subNum = am.group(2);
                        String prefix = (questionIndex != null) ? ("第" + questionIndex + "题") : "该题";
                        errors.add(prefix + "：第" + subNum + "小题标识需为括号形式（示例：'【题目类型】（" + subNum + "）' 或 '【题目类型】(" + subNum + ")'）");
                    } else {
                        // 回退：仅提取题型，用于报错显示
                        Matcher bm = Pattern.compile(".*【([\\u4e00-\\u9fa5]+题)】.*").matcher(plain);
                        if (bm.find()) {
                            typeName = bm.group(1);
                        }
                        String prefix = (questionIndex != null) ? ("第" + questionIndex + "题") : "该题";
                        errors.add(prefix + "：小题类型标识格式错误，需 '【题目类型】（数字）' 或 '【题目类型】(数字)'");
                    }
                }

                // 类型支持性校验（对类型名先做同义词规范化，再按系统标准集合校验）
                String canonical = normalizeTypeName(typeName);
                if (canonical != null && !CANONICAL_TYPES.contains(canonical)) {
                    String prefix = (questionIndex != null) ? ("第" + questionIndex + "题") : "该题";
                    String which = (subNum != null) ? ("第" + subNum + "小题") : "小题";
                    errors.add(prefix + "：" + which + "题目类型不支持：'" + typeName + "'，支持类型：" + String.join("、", CANONICAL_TYPES));
                }

                // 设置当前小题类型（用于后续内容聚合）：使用规范化后的类型名
                currentType = (canonical != null) ? canonical : currentType;

                // 不要小题标识本身，只保存后续节点
                String cleaned = html.trim();
                if (!cleaned.isEmpty() && !cleaned.equals("<p></p>")) {
                    subQBuilder.append(cleaned);
                }
                continue;
            }

            // 仅编号式小题（无类型）：行首为（数字）或(数字)的段落
            // 题干阶段的括号编号视为题干内容；进入小题段后才视为缺少类型的小题
            if (foundStemMarker) {
                Matcher pm = Pattern.compile("^\\s*[（(]\\s*(\\d+)\\s*[)）].*").matcher(plain);
                if (pm.find()) {
                    String n = pm.group(1);
                    parenSubNums.add(n);
                    if (!subSectionStarted) {
                        // 题干阶段：作为题干内容，不立即报错
                        preStemParenNums.add(n);
                    } else {
                        // 已进入小题段：该编号段缺少类型标识，记录错误
                        missingTypeSubNums.add(n);
                    }
                }
            }

            // 内容保存（包括 <p>、<ul>、<table>）
            if (inStem) {
                stemBuilder.append(html);
            } else if (inSubQ) {
                subQBuilder.append(html);
            }
        }
        // 模板校验：必须包含【题干】并且以【题目结束】结束
        if (!foundStemMarker) {
            errors.add("缺少【题干】标识");
        }
        if (!foundEndMarker) {
            errors.add("缺少【题目结束】标识");
        }

        // 若存在任何括号编号但缺少对应的【题目类型】标识，则提示缺少小题类型（支持部分缺失和全部缺失两种情况）
        if (!missingTypeSubNums.isEmpty()) {
            StringBuilder nums = new StringBuilder();
            int i = 0;
            for (String n : missingTypeSubNums) {
                if (i++ > 0) nums.append("、");
                nums.append("（").append(n).append("）");
            }
            String prefix = (questionIndex != null) ? ("第" + questionIndex + "题") : "该题";
            errors.add(prefix + "：检测到小题编号" + nums + "但缺少小题类型标识，需使用'【题目类型】（数字）'或'【题目类型】(数字)'");
        }

        // 若全题未出现任何【题目类型】且题干阶段出现括号编号，则认为缺少小题类型（用于没有类型但有小题的题目）
        if (!foundTypeSubMarker && !preStemParenNums.isEmpty()) {
            StringBuilder nums = new StringBuilder();
            int i = 0;
            for (String n : preStemParenNums) {
                if (i++ > 0) nums.append("、");
                nums.append("（").append(n).append("）");
            }
            String prefix = (questionIndex != null) ? ("第" + questionIndex + "题") : "该题";
            errors.add(prefix + "：检测到小题编号" + nums + "但缺少小题类型标识，需使用'【题目类型】（数字）'或'【题目类型】(数字)'");
        }

        if (!errors.isEmpty()) {
            String prefix = (questionIndex != null) ? ("第" + questionIndex + "题模板错误：") : "模板错误：";
            throw new ServiceException(prefix + String.join("；", errors));
        }

        return new Question(stemBuilder.toString(), subQuestions);
    }

    // 示例测试
    public static void main(String[] args) throws Exception {
        File input = new File("C:\\Users\\Administrator\\Desktop\\34.txt"); // 替换成你的文件路径
        Question q = parseQuestion(String.valueOf(input));

        System.out.println("题干HTML：");
        System.out.println(q.getStemHtml());

        System.out.println("\n小题：");
        for (SubQuestion sq : q.getSubQuestions()) {
            System.out.println("题型: " + sq.getType());
            System.out.println("内容: " + sq.getHtml());
            System.out.println("---------------------------------------------------");
        }
    }
}
